/*
 * @Author: 张宇飞
 * @Date: 2020-03-04 17:31:50
 * @LastEditors: 张宇飞
 * @LastEditTime: 2020-03-05 16:22:32
 * @Description: 演示如何使用线程私有数据
 * pthread_key 提供了同名不同值的方式访问数据。无论哪个线程调用
 * pthread_key_create 所有线程都是可以访问 key 的值
 * @Email: zhangyufei49@163.com
 */
#include <stdio.h>
#include "utils.h"

#define print_test_header() \
    fprintf(stderr, "\n------------ %s ------------\n\n", __func__)

static pthread_key_t key;

static void* a(void* arg) {
    pthread_setspecific(key, (const void*)10);
    fprintf(stderr, "in thread a get data: %d\n",
            (int)pthread_getspecific(key));
    return NULL;
}

static void* b(void* arg) {
    pthread_setspecific(key, (const void*)99);
    fprintf(stderr, "in thread b get data: %d\n",
            (int)pthread_getspecific(key));
    return NULL;
}

static void* c(void* arg) {
    pthread_setspecific(key, (const void*)20);
    // 在linux 上，下面一行将获得 0 并且 on_key_destroy不会被触发了
    pthread_key_delete(key);
    // 这里获取的值在 linux 上将是 0
    fprintf(stderr, "in thread b get data: %d\n",
            (int)pthread_getspecific(key));
    return NULL;
}

static void on_key_destroy(void* a) {
    fprintf(stderr, "on key destroy: %d\n", (int)a);
}

static void test_base() {
    print_test_header();
    // 该函数从TSD池中分配一项，将其值赋给key供以后访问使用
    // 如果destr_function不为空，在线程退出（pthread_exit()）
    // 时将以key所关联的数据为参数调用destr_function()，以释放分配的缓冲区
    pthread_key_create(&key, on_key_destroy);

    run_threads(a, b, NULL);
    // 你会发现 on_key_destroy 先于这里显示
    // 这说明 on_key_destroy 在线程退出的时候调用
    fprintf(stderr, "thread finish\n");
    // 这个函数只清理 key ，让其他线程可以再次从key池中申请它
    pthread_key_delete(key);
}

static void test_destroy_key() {
    print_test_header();
    pthread_key_create(&key, on_key_destroy);
    run_threads(c, NULL);
    fprintf(stderr, "thread finish\n");
}

int main(int argc, char const* argv[]) {
    test_base();
    test_destroy_key();

    return 0;
}